package com.tiancheng.trade.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.order.bo.CouponBO;
import com.tiancheng.trade.order.enums.CouponStatusEnum;
import com.tiancheng.trade.order.feign.CouponSystemService;
import com.tiancheng.trade.order.mapper.CouponMapper;
import com.tiancheng.trade.order.model.Coupon;
import com.tiancheng.trade.order.service.CouponService;
import com.tiancheng.trade.order.util.ObjectConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Auther: ld
 * @Date: 2024/2/24 14:30
 * @Param ${tags}
 * @Description:
 */
@Service
@Slf4j
public class CouponServiceImpl implements CouponService {

    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private CouponSystemService couponSystemService;

    @Override
    public List<CouponBO> lock(List<CouponBO> couponBOS) throws BusinessException {
        BusinessErrorInfoEnum.ORDER_CREATE_NOT_SUPPORT_COUPON_ERROR.assertIsTrue(CollectionUtils.isEmpty(couponBOS));
        if (couponBOS.size() == 0) return couponBOS;
        /*  不需要查询，券是否可用由优惠券中心判断，不可用直接返回锁定失败
        // 查询优惠券系统补齐信息
        List<CouponBO> futures = couponBOS.stream().map(couponBO ->
                couponSystemService.get(couponBO)).collect(Collectors.toList());

        // 如果没有获取优惠券信息，说明下单附带的优惠券无效，抛出异常禁止下单
        for (CouponBO couponBO : futures) {
            BusinessErrorInfoEnum.ORDER_CREATE_COUPON_LOCK.assertIsTrue(couponBO.getCouponStatus().equals(CouponStatusEnum.no_bind.getCode()));
        }*/

        // 锁定优惠券
        List<CouponBO> futures = couponBOS.stream().map(couponBO -> couponSystemService.lock(couponBO)).collect(Collectors.toList());
        List<CouponBO> lockedCoupons = new ArrayList<>();
        for (CouponBO couponBO : futures) {
            if (couponBO.getCouponStatus().equals(CouponStatusEnum.lock.getCode())) {
                lockedCoupons.add(couponBO);
            }
        }

        // 如果优惠券中，有任意一张锁定失败，全部回滚解锁，抛出异常禁止下单
        if (lockedCoupons.size() != couponBOS.size()) {
            lockedCoupons.forEach(couponBO -> couponSystemService.unlock(couponBO));
            BusinessErrorInfoEnum.ORDER_CREATE_COUPON_LOCK.assertFail();
        }
        return lockedCoupons;
    }

    @Override
    public void unlock(List<CouponBO> couponBOS) {
        couponBOS.forEach(couponBO -> couponSystemService.unlock(couponBO));
    }

    @Override
    public void unlock(String uid, String[] orderIds, String[] subOrderIds) throws BusinessException {
        QueryWrapper<Coupon> conditions = new QueryWrapper<>();
        conditions.in("order_id", orderIds);
        if (subOrderIds != null && subOrderIds.length > 0) {
            conditions.in("sub_order_id", subOrderIds);
        }
        List<Coupon> coupons = couponMapper.selectList(conditions);
        if (coupons.size() == 0) return;

        coupons.forEach(coupon -> {
            CouponBO couponBO = new CouponBO();
            couponBO.setUid(uid);
            couponBO.setOrderId(coupon.getOrderId());
            couponBO.setSubOrderId(coupon.getSubOrderId());
            couponBO.setCouponCode(coupon.getCouponCode());
            couponSystemService.unlock(couponBO);
        });
    }

    @Override
    public int create(List<CouponBO> couponBOS) throws BusinessException {
        List<Coupon> coupons = couponBOS.stream().map(couponBO -> {
            Coupon coupon = ObjectConvertUtil.convert(couponBO, Coupon.class).get();
            coupon.setCreatedDt(LocalDateTime.now());
            return coupon;
        }).collect(Collectors.toList());
        return couponMapper.saveBatch(coupons);
    }

    @Override
    public void writeOff(String uid, String[] orderIds, String[] subOrderIds) throws BusinessException {
        QueryWrapper<Coupon> conditions = new QueryWrapper<>();
        conditions.in("order_id", orderIds);
        if (subOrderIds != null && subOrderIds.length > 0) {
            conditions.in("sub_order_id", subOrderIds);
        }
        List<Coupon> coupons = couponMapper.selectList(conditions);
        if (coupons.size() == 0) return;

        coupons.forEach(coupon -> {
            CouponBO couponBO = ObjectConvertUtil.convert(coupon, CouponBO.class, "rawInfo").get();
            couponBO.setUid(uid);
            couponSystemService.writeOff(couponBO);
        });
    }

    @Override
    public List<Coupon> find(String[] orderIds) {
        QueryWrapper<Coupon> conditions = new QueryWrapper<>();
        conditions.in("order_id", orderIds);
        return couponMapper.selectList(conditions);
    }

    @Override
    public List<Coupon> getCouponList(String orderId) {
        QueryWrapper<Coupon> conditions = new QueryWrapper<>();
        conditions.eq("order_id", orderId);
        conditions.isNull("sub_order_id");
        return couponMapper.selectList(conditions);
    }

    @Override
    public List<Coupon> getSubCouponList(String subOrderId) {
        QueryWrapper<Coupon> conditions = new QueryWrapper<>();
        conditions.eq("sub_order_id", subOrderId);
        return couponMapper.selectList(conditions);
    }

    @Override
    public List<Coupon> getCouponByOrderId(List<String> orderIds) {
        return couponMapper.getCouponByOrderId(orderIds);
    }

    @Override
    public void returnCoupon(String uid, String[] orderIds, String[] subOrderIds) throws BusinessException {
        QueryWrapper<Coupon> conditions = new QueryWrapper<>();
        conditions.in("order_id", orderIds);
        if (subOrderIds != null && subOrderIds.length > 0) {
            conditions.in("sub_order_id", subOrderIds);
        }
        List<Coupon> coupons = couponMapper.selectList(conditions);
        if (coupons.size() == 0) return;

        coupons.forEach(coupon -> {
            CouponBO couponBO = ObjectConvertUtil.convert(coupon, CouponBO.class, "rawInfo").get();
            couponBO.setUid(uid);
            couponSystemService.returnCoupon(couponBO);
        });
    }

}
